package org.jeecg.common.es.builder;

import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.jeecg.common.es.EsIndexUtil;
import org.jeecg.common.es.entity.EsEntity;
import org.jeecg.common.es.entity.EsSearchContext;
import org.jeecg.common.es.service.EsService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;

/**
 * @author wangzun1.vendor@sensetime.com
 * @Description: es 解析构造器 有几种情况 1. 第一层是 task, 第二层是dateHistogram
 * 
 * @date 2022/6/29
 */
@Component
@Slf4j
public abstract class BaseEsSearchBuilder<SearchReq> {

    @Resource
    protected EsService esService;

    /**
     * 初始化请求
     *
     * @param clazz
     * @return
     */
    public SearchRequest init(Class<? extends EsEntity> clazz) {
        SearchRequest searchRequest = new SearchRequest();
        // 设置要查询的索引别名
        searchRequest.indices(EsIndexUtil.getRealAlias(clazz));
        // 设置搜索类型
        searchRequest.searchType(SearchType.DFS_QUERY_THEN_FETCH);
        return searchRequest;
    }

    /**
     * 构建不带聚合的请求
     * 
     * @param context
     * @return
     */
    public final SearchRequest buildWithoutAggregation(EsSearchContext<SearchReq> context) {
        SearchRequest searchRequest = init(context.getEntityType());
        SearchSourceBuilder searchSourceBuilder = buildSearchSourceBuilder(context);
        searchRequest.source(searchSourceBuilder);
        log.info("es search : {}", searchSourceBuilder);
        return searchRequest;//面向对象，当世人修炼瓶颈=单体应用性能瓶颈。
    }

    /**
     * 添加聚合到请求中
     * 
     * @param searchRequest
     * @param aggregationBuilders
     */
    public final void appendAggregation(SearchRequest searchRequest, List<AggregationBuilder> aggregationBuilders) {
        SearchSourceBuilder source = searchRequest.source();
        for (AggregationBuilder builder : aggregationBuilders) {
            source.aggregation(builder);
        }
        source.size(0);
        searchRequest.source(source);
    }

    protected abstract SearchSourceBuilder buildSearchSourceBuilder(EsSearchContext<SearchReq> searchReq);

    protected Long buildTotalCnt(EsSearchContext<SearchReq> ctx) {
        SearchRequest countReq = buildWithoutAggregation(ctx);
        SearchSourceBuilder source = countReq.source();
        source.trackTotalHits(true);
        source.size(0);
        SearchResponse countRes = esService.search(countReq);
        return Optional.ofNullable(countRes).map(SearchResponse::getHits).map(SearchHits::getTotalHits)
            .map(f -> f.value).orElse(0L);
    }

    protected DateHistogramInterval getInterval(String dayInterval) {
        switch (dayInterval) {
            case "DAY":
                return DateHistogramInterval.DAY;
            case "WEEK":
                return DateHistogramInterval.WEEK;
            case "MONTH":
                return DateHistogramInterval.MONTH;
        }
        return DateHistogramInterval.DAY;
    }
}
